grammar Program;

options {
backtrack=true;
output=AST;
ASTLabelType=CommonTree;
}

tokens {
MAINMETHOD;
CLASS;
VARDECL;
METHOD;
BLOCK;
ARG;
FUNC_RETURN;
METHOD_CALL;
PROG;
}

@header {
package program;
}

@lexer::header {
package program;
}

prog: mainMethod (methodDecl* | WS+) -> ^(PROG mainMethod methodDecl*)
;

mainMethod:
    'main' '(' ')' '{' statement* '}' -> ^(MAINMETHOD statement*)
;

varDecl: type ID ';' -> ^(VARDECL type ID)
;

methodDecl: returnType ID '(' ( formalParameter (',' formalParameter)* )? ')'
block   -> ^(METHOD returnType ID formalParameter* block)
;

block: '{' varDecl* statement* funcReturn? '}' -> ^(BLOCK varDecl* statement* funcReturn?)
;

funcReturn: RETURN exp ';' -> ^(FUNC_RETURN exp)
;

formalParameter
    : type ID -> ^(ARG type ID)
;

statement: varDecl | assignStatement | printStatement | conditionalStatement
 | whileStatement | methodCall
;

methodCall: ID '(' exp (',' exp)* ')' ';' -> ^(METHOD_CALL ID exp*)
;

whileStatement: WHILE '(' exp ')' '{' statement+ '}' -> ^(WHILE exp statement+)
;

conditionalStatement: IF '(' exp ')' statement ELSE statement -> ^(IF exp statement ^(ELSE statement) )
;

assignStatement: ID ASSIGN exp ';' -> ^(ASSIGN ID exp )
;

printStatement: PRINT exp ';' -> ^(PRINT exp )
;

exp: additionExp | simpleExp | lessThanExp | equalityExp
;

simpleExp: ID | INT
;

additionExp: simpleExp ADD simpleExp  -> ^(ADD simpleExp simpleExp )
;

lessThanExp: simpleExp LT simpleExp  -> ^(LT simpleExp simpleExp )
;

equalityExp: simpleExp EQ simpleExp -> ^(EQ simpleExp simpleExp )
;

type: 'int' | 'boolean' 
;

returnType: type | 'void'
;

PUBLIC: 'public';
IF: 'if';
WHILE: 'while';
ELSE: 'else';
RETURN: 'return';
PRINT: 'print';
ASSIGN: '=';
EQ: '==';
ADD: '+';
LT: '<';
ID : ('a'..'z' |'A'..'Z' )+ ;
INT : '0'..'9' + ;
OP : '+' | '-' | '*';
WS : (' ' |'\t' |'\n' |'\r' )+ {skip();};


